package cn.hutool.setting.i18n;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.setting.Setting;

import java.nio.charset.Charset;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 多语言配置读取工具, 会读取一个不带区域的默认配置文件作为默认配置;存在区域配置就区域配置优先,没有再用默认
 * @author sg
 */
public class I18nReadUtil {

	static final String[] extensionName = new String[]{".setting"};

	/**
	 * 保存区域对应的setting文件
	 */
	static final ConcurrentHashMap<String, Setting> map = new ConcurrentHashMap<>();

	/**
	 * 资源名
	 */
	String name;
	/**
	 * 分隔符  读取特定语言时, 资源文件名称等于name+separator+locale
	 */
	String separator;
	/**
	 * 默认区域,这个在固定配置的情况下使用,如配置本地软件的语言
	 */
	String localeDef;

	/**
	 * 编码格式
	 */
	Charset charset;
	/**
	 * 是否使用变量
	 */
	boolean isUseVariable;


	public I18nReadUtil(String name, String separator, String localeDef, Charset charset, boolean isUseVariable) {
		this.name = name;
		this.separator = separator;
		this.localeDef = localeDef;
		this.charset = charset;
		this.isUseVariable = isUseVariable;
	}

	/**
	 * @param name      配置文件名称
	 * @param separator 配置文件和区域之间的分隔符
	 * @param localeDef 默认区域,可以为null
	 * @return {@link I18nReadUtil}
	 */
	public static I18nReadUtil init(String name, String separator, String localeDef) {
		return init(name, separator, localeDef, CharsetUtil.CHARSET_UTF_8, false);
	}

	/**
	 * @param name 配置文件名称
	 * @param separator 配置文件和区域之间的分隔符
	 * @param localeDef 默认区域,可以为null
	 * @param encode 编码
	 * @param isUseVariable 是否使用变量
	 * @return {@link I18nReadUtil}
	 */
	public static I18nReadUtil init(String name, String separator, String localeDef, Charset encode, boolean isUseVariable) {
		I18nReadUtil settingExt = new I18nReadUtil(name, separator, localeDef, encode, isUseVariable);
		try {
			Setting load = settingExt.load(null);
			map.put(name, load);
		} catch (Exception e) {
			map.put(name, new Setting());
		}
		settingExt.get("", localeDef);
		return settingExt;
	}

	public String get(String key) {
		return get(key, localeDef);
	}

	/**
	 * @param key    要获取的键值对名称
	 * @param locale 语言环境
	 * @return {@link String} 如果没有获取到,则使用默认语言配置
	 */
	public String get(String key, String locale) {
		String lk = convertTheKey(locale); // 多语言键
		if (map.containsKey(lk)) {
			return map.get(lk).getStr(key);
		}
		Setting def;
		def = map.get(name);
		synchronized (this) {
			if (locale != null) {
				try {
					Setting load = load(locale);
					Setting set = new Setting().addSetting(def).addSetting(load);
					map.put(lk, set);
					return set.getStr(key);
				} catch (Exception e) {
					map.put(lk, def);
				}
			} else {
				map.put(lk, def);
			}
		}
		return def.getStr(key);
	}

	/**
	 * 把语言环境转换成map的key
	 *
	 * @param locale 语言环境
	 * @return {@link String}
	 */
	private String convertTheKey(String locale) {
		String lk = name;
		if (locale != null && !locale.isEmpty()) {
			lk = lk + separator + locale;
		}
		return lk;
	}


	/**
	 * 加载多语言配置
	 * @param locale 地区配置
	 * @return {@link Setting}
	 */
	private Setting load(String locale) {
		String lk = convertTheKey(locale);
		return new Setting(lk + extensionName[0], charset, isUseVariable);
	}
}
